package com.imooc.springcloud;

import com.google.common.util.concurrent.RateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * @author caryguan
 * @version V1.0
 * @Package com.imooc.springcloud
 * @date 2020/10/17 17:00
 */

@RestController
@Slf4j
public class Controller {

    /**
     * rateLimiter的使用场景: rateLimiter适用于对单机资源比较敏感的服务器,并不适用与分布式限流方案,因为一旦集群部署后,单机的限流方案效果
     * 十分有限,如果我们要限流的其实是上游的中间件或者数据库,单机限流方案rateLimiter又不能互相通信,服务器之间不共享,我们有更好的分布式限流
     * 方案,所以,这个单机版的rateLimiter限流只适用于比如:单体计算逻辑十分复杂,为了节省硬件资源占用,可以考虑单机的限流方案
     */

    /**
     *  rateLimiter没秒创建两个通行证API
     */
    RateLimiter limiter = RateLimiter.create(2.0);

    /**
     * 非阻塞限流方式,尝试获取方法
     * @param count
     * @return
     */
    @GetMapping("/tryAcquire")
    public String tryAcquire(Integer count) {
        //调用limiter尝试获取API并将请求个数也传入
        if (limiter.tryAcquire(count)) {
            log.info("success,rate is {}", limiter.getRate());
            return "success";
        } else {
            log.info("fail,rate is {}", limiter.getRate());
            return "fail";
        }
    }

    /**
     * 限定时间的非阻塞限流,我注意到了如果传入的count和timeout的关系,性能优化机制:如果规定timeout的时间产生的令牌数满足不了请求count数
     * 那么会快速返回,节约性能
     * @param count
     * @param timeout
     * @return
     */
    @GetMapping("/tryAcquireWithTimeout")
    public String tryAcquireWithTimeout(Integer count,Integer timeout) {
        //调用limiter尝试获取API并将请求个数也传入
        if (limiter.tryAcquire(count,timeout, TimeUnit.SECONDS)) {
            log.info("success,rate is {}", limiter.getRate());
            return "success";
        } else {
            log.info("fail,rate is {}", limiter.getRate());
            return "fail";
        }
    }

    /**
     * 同步阻塞的限流方式,如果令牌不足,则会等待!!!
     * @return
     */
    @GetMapping("/acquire")
    public String acquire(Integer count){
        limiter.acquire(count);
        log.info("success,rate is {}", limiter.getRate());
        return "success";
    }
}